package com.citywithincity.api.post.impl;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;

import javax.net.ssl.HttpsURLConnection;

import com.citywithincity.api.post.ApiPost;
import com.citywithincity.api.post.ApiResponse;
import com.citywithincity.utils.HttpUtil;
import com.citywithincity.utils.HttpsUtil;
import com.citywithincity.utils.IoUtil;
import com.citywithincity.utils.JsonUtil;
import com.citywithincity.utils.MD5Util;
import com.damai.error.ApiError;
import com.damai.utils.Arguments;
import com.damai.utils.Caster;
import com.fasterxml.jackson.annotation.JsonUnwrapped;

public class ShareChargePost implements ApiPost {

	private String baseUrl;

	public ShareChargePost(String baseUrl, String deviceId) {
		this.baseUrl = baseUrl;
		this.deviceId = deviceId;
	}
	
	public String getDeviceId() {
		return this.deviceId;
	}
	
	public String getToken() {
		return this.token;
	}
	
	public String getRefreshToken() {
		return refreshToken;
	}

	public static class ShareChargeError extends RuntimeException {

		/**
		 * 
		 */
		private static final long serialVersionUID = -5083787644370948298L;

		private String error;

		private String code;

		public String getError() {
			return error;
		}

		public void setError(String error) {
			this.error = error;
		}

		public String getCode() {
			return code;
		}

		public void setCode(String code) {
			this.code = code;
		}

	}

	private String readContent(HttpURLConnection connection) throws IOException {
		try {
			return IoUtil.readContent(connection.getInputStream(), "UTF-8");
		} catch (IOException e) {
			return IoUtil.readContent(connection.getErrorStream(), "UTF-8");
		}
	}

	private ApiResponse getResponse(HttpURLConnection connection) throws IOException {
		String respones = readContent(connection);
		if (respones == null) {
			return new ApiResponse(null, null, false);
		}
		if ("null".equals(respones)) {
			return new ApiResponse(null, null, false);
		}

		if (respones.startsWith("[")) {
			return new ApiResponse(null, JsonUtil.readList(respones), false);
		}

		if(respones.startsWith("\"")) {
			return new ApiResponse(null, JsonUtil.getMapper().readValue(respones,String.class), false);
		}
		
		return new ApiResponse(null, JsonUtil.read(respones), false);
	}

	private HttpURLConnection create(String api, Map<String, Object> args) throws IOException {
		String content = JsonUtil.toJson(args);
		HttpURLConnection connection = HttpUtil.createConnection(baseUrl + api, "UTF-8", content.length());
		
		connection.setRequestProperty("token", token);
		
		DataOutputStream out = null;
		try{
			//write
			if(content!=null){
				out = new DataOutputStream(connection.getOutputStream());
				out.write(content.getBytes());
				out.flush();
			}
			return connection;
		}finally{
			IoUtil.close(out);
		}
	}
	

	@Override
	public ApiResponse post(String api, Map<String, Object> args, int crypt) throws IOException {
		HttpURLConnection connection = create(api, args);
		int code = connection.getResponseCode();
		if (code == 200) {
			return getResponse(connection);
		}

		if (code == 418) {
			// throw new ApiError(error, reason);
			// return new ApiResponse(raw);

			System.err.println("服务器报错");

			return null;
		}

		if (code == 401) {

			System.err.println("需要登录");
			return null;
		}

		if (code == 503) {
			System.err.println("服务器错误");
			return null;
		}

		if (code == 504) {
			System.err.println("服务器超时");
			return null;
		}

		if (code == 403) {
			String response = readContent(connection);
			Map<String, Object> error = JsonUtil.read(response);
			String errCode = Caster.to(error.get("code"), String.class);
			if ("none".equals(errCode)) {
				// none
				// 申请token
				requestToken();
				return post(api, args, crypt);
			} else if ("timeout".equals(errCode)) {
				// timeout
				refreshToken();
				return post(api, args, crypt);
			} else {
				// error
				System.err.println("refreshToken过期需要登录");
			}
		}

		return null;
	}

	private String token;
	private String publicKey;
	private String refreshToken;
	private String privateKey;
	private String deviceId;

	private void requestToken() throws IOException {
		HttpURLConnection connection = create("passport/requestToken",
				Arguments.newMap().put("deviceId", deviceId).get());
		int code = connection.getResponseCode();
		if (code == 200) {
			ApiResponse response = getResponse(connection);
			token = response.getString("token");
			return;
		}
		
		throw new ApiError("获取token失败");
	}
	
	private void refreshToken() throws IOException {
		HttpURLConnection connection = create("passport/refreshToken",
				Arguments.newMap()
					.put("deviceId", deviceId)
					.put("refreshToken", refreshToken )
					.get());
		int code = connection.getResponseCode();
		if (code == 200) {
			ApiResponse response = getResponse(connection);
			if(response.getBool("success")) {
				Map<String, Object> map = response.getMap("token");
				token = (String) map.get("token");
				String refreshToken = (String) map.get("refreshToken");
				if(refreshToken!=null) {
					this.refreshToken = refreshToken;
				}
				return;
			}
			
			
		}
		
		throw new ApiError("refreshToken换token失败,需要登录");
	}

	public void setRefreshToken(String refreshToken) {
		this.refreshToken = refreshToken;
	}

	public void setToken(String token) {
		this.token = token;
	}
}
